package com.qianli.cashmama.trade.application.bill;

import com.fqgj.common.api.Page;
import com.fqgj.common.api.Response;
import com.fqgj.common.api.annotations.ParamsValidate;
import com.fqgj.common.utils.CollectionUtils;
import com.fqgj.common.utils.StringUtils;
import com.fqgj.common.utils.TimeUtils;
import com.google.common.collect.Lists;
import com.qianli.cashmama.trade.client.bill.BillQueryService;
import com.qianli.cashmama.trade.client.bill.request.BillListRequest;
import com.qianli.cashmama.trade.client.bill.request.RepaymentQueryRequest;
import com.qianli.cashmama.trade.client.bill.request.RepaymentTrialRequest;
import com.qianli.cashmama.trade.client.bill.response.BillListResponse;
import com.qianli.cashmama.trade.client.bill.response.POrderPrePaymentResponse;
import com.qianli.cashmama.trade.client.bill.response.TradeDetailResponse;
import com.qianli.cashmama.trade.client.vo.BillRepayment2VO;
import com.qianli.cashmama.trade.client.vo.BillRepaymentDetailVO;
import com.qianli.cashmama.trade.client.vo.BillVO;
import com.qianli.cashmama.trade.client.vo.POrderPrePaymentVO;
import com.qianli.cashmama.trade.common.config.TimerRecord;
import com.qianli.cashmama.trade.common.enums.BillPaidStatusEnum;
import com.qianli.cashmama.trade.common.enums.TradeBorrowDurationEnum;
import com.qianli.cashmama.trade.common.exceptions.TradeException;
import com.qianli.cashmama.trade.common.utils.CalculatorUtils;
import com.qianli.cashmama.trade.dao.POrderPrePaymentDao;
import com.qianli.cashmama.trade.dao.TBillDao;
import com.qianli.cashmama.trade.dao.TBillRepaymentDetailDao;
import com.qianli.cashmama.trade.dao.TTradeDao;
import com.qianli.cashmama.trade.domain.model.BillBase;
import com.qianli.cashmama.trade.domain.model.TradeBase;
import com.qianli.cashmama.trade.entity.POrderPrePaymentEntity;
import com.qianli.cashmama.trade.entity.TBillEntity;
import com.qianli.cashmama.trade.entity.TBillRepaymentDetailEntity;
import com.qianli.cashmama.trade.entity.TTradeEntity;
import com.qianli.cashmama.trade.integration.product.ProductIntegrationService;
import com.qianli.cashmama.trade.integration.product.dto.ProductDto;
import com.qianli.cashmama.trade.repo.BillBaseRepository;
import com.qianli.cashmama.trade.repo.TradeBaseRepository;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
import org.springframework.beans.BeanUtils;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.stereotype.Service;

import java.math.BigDecimal;
import java.util.*;
import java.util.stream.Collectors;
/**
 * Created with IntelliJ IDEA.
 * User: sm
 * Date: 2017/8/1
 * Time: 下午9:06
 */
@Service("billQueryService")
public class BillQueryServiceImpl implements BillQueryService {
    private static final Logger LOGGER = LoggerFactory.getLogger(BillQueryServiceImpl.class);
    @Autowired
    private BillBaseRepository billBaseRepository;

    @Autowired
    private TradeBaseRepository tradeBaseRepository;

    @Autowired
    private TBillDao billDao;

    @Autowired
    private TTradeDao tradeDao;

    @Autowired
    private TBillRepaymentDetailDao repaymentDetailDao;

    @Autowired
    private ProductIntegrationService productIntegrationService;

    @Autowired
    private POrderPrePaymentDao pOrderPrePaymentDao;
    @Autowired
    private TBillRepaymentDetailDao tBillRepaymentDetailDao;

    @Override
    @ParamsValidate
    @TimerRecord
    public Response<BillListResponse> queryBillList(BillListRequest billListRequest) {
        try {
            TradeBase tradeBase = tradeBaseRepository.load(billListRequest.getTradeNo());
            boolean tradeNotExist = tradeBase == null;
            if (tradeNotExist) {
                return Response.ok().putData(null);
            }

            List<BillBase> billBaseList = billBaseRepository.getBillListByTradeNo(billListRequest.getTradeNo());
            if (CollectionUtils.isEmpty(billBaseList)) {
                return Response.ok().putData(null);
            }

            ProductDto productInfoByCode = productIntegrationService.getProductInfoByCode(tradeBase.getProductCode());
            tradeBase.setBorrowRatio(productInfoByCode.getBorrowRatio());

            List<BillVO> billListResultVOList = new ArrayList<>(billBaseList.size());
            for (int i = 0; i < billBaseList.size(); i++) {
                BillBase billBase = billBaseList.get(i);
                BillVO billVO = billBase2BillVO(tradeBase, billBase);
                billListResultVOList.add(billVO);
            }
            return Response.ok().putData(new BillListResponse(billListResultVOList));
        } catch (TradeException e) {
            LOGGER.error("查询账单列表失败,tradeNo:{}", billListRequest.getTradeNo(), e);
            return Response.ok().putData(null);
        }
    }

    /**
     * 交易详情
     *
     * @param tradeNo
     * @return
     */
    @Override
    @TimerRecord
    public Response<TradeDetailResponse> queryTradeDetailByTradeNo(String tradeNo) {
        try {
            TradeBase tradeBase = tradeBaseRepository.load(tradeNo);
            boolean tradeNotExist = tradeBase == null;
            if (tradeNotExist) {
                return Response.ok().putData(null);
            }

            TradeDetailResponse detailResponse = new TradeDetailResponse();
            BeanUtils.copyProperties(tradeBase, detailResponse);
            if (detailResponse.getTradeOrderStatus() != null) {
                detailResponse.setTradeOrderStatusName(detailResponse.getTradeOrderStatus().getDesc());
            }
            List<BillBase> billBaseList = billBaseRepository.getBillListByTradeNo(tradeNo);
            List<BillVO> billVOList = new ArrayList<>();
            if (CollectionUtils.isNotEmpty(billBaseList)) {
                for (BillBase billBase : billBaseList) {
                    BillVO billVO = new BillVO();
                    BeanUtils.copyProperties(billBase, billVO);
                    billVOList.add(billVO);
                }
            }
            detailResponse.setBillVOList(billVOList);
            return Response.ok().putData(detailResponse);
        } catch (TradeException e) {
            LOGGER.error("查询账单列表失败,tradeNo:{}", tradeNo, e);
            return Response.ok().putData(null);
        }
    }


    @Override
    @TimerRecord
    public Response<BillVO> queryByBillNo(String billNo) {
        Response<BillVO> response = new Response<>();
        BillBase billBase = billBaseRepository.getBillByBillNo(billNo);
        if (billBase == null) {
            LOGGER.error("账单不存在,billNo:{}", billNo);
            return response.ok().putData(null);
        }

        TradeBase tradeBase = tradeBaseRepository.load(billBase.getTradeNo());
        if (tradeBase == null) {
            LOGGER.error("交易不存在,billNo:{},tradeNo:{}", billNo, billBase.getTradeNo());
            return response.ok().putData(null);
        }

        ProductDto productInfoByCode = productIntegrationService.getProductInfoByCode(tradeBase.getProductCode());
        tradeBase.setBorrowRatio(productInfoByCode.getBorrowRatio());

        return response.ok().putData(billBase2BillVO(tradeBase, billBase));
    }

    @Override
    @TimerRecord
    public Response<List<BillVO>> queryByOrderBillId(List<Long> orderBillIds) {
        Response<List<BillVO>> response = new Response<>();
        if (CollectionUtils.isEmpty(orderBillIds)) {
            return response.ok().putData(null);
        }

        List<BillVO> billVOList = new ArrayList<>();
        List<TBillEntity> billEntityList = billDao.selectListByOrderBillIds(orderBillIds);
        for (TBillEntity tBillEntity : billEntityList) {
            BillVO billVO = new BillVO().setBillNo(tBillEntity.getBillNo());
            billVOList.add(billVO);
        }

        return response.ok().putData(billVOList);
    }

    @Override
    @TimerRecord
    public Response<List<BillVO>> queryByUserCode(String userCode) {
        Response<List<BillVO>> response = new Response<>();
        Page page = new Page(100);
        List<TTradeEntity> tradeEntityList = tradeDao.selectListByUserCode(userCode, page);
        if (CollectionUtils.isEmpty(tradeEntityList)) {
            return response.ok().putData(null);
        }

        Map<String, TTradeEntity> tradeNoMap = new HashMap<>();
        for (TTradeEntity tradeEntity : tradeEntityList) {
            tradeNoMap.put(tradeEntity.getTradeNo(), tradeEntity);
        }

        List<String> tradeNos = tradeEntityList.parallelStream().map(TTradeEntity::getTradeNo).collect(Collectors.toList());
        List<BillVO> billVOList = new ArrayList<>();
        List<TBillEntity> billEntityList = billDao.selectPaidListByTradeNos(tradeNos);

        for (TBillEntity billEntity : billEntityList) {
            ProductDto productInfoByCode = productIntegrationService.getProductInfoByCode(billEntity.getProductCode());
            BillVO billVO = new BillVO().setBillNo(billEntity.getBillNo())
                    .setTradeNo(billEntity.getTradeNo())
                    .setBorrowCapital(billEntity.getBorrowCapital().toString())
                    .setReceivedCapital(billEntity.getReceivedCapital().toString())
                    .setProductCategory(billEntity.getProductCategory())

                    .setCurrentPeriod(billEntity.getCurrentPeriod())
                    .setPaidCapital(billEntity.getPaidCapital().toString())
                    .setPaidStatus(BillPaidStatusEnum.concertByStatus(billEntity.getPaidStatus()))
                    .setRepaymentDate(TimeUtils.getDate("yyyy-MM-dd", billEntity.getRepaymentDate()))

                    .setServiceFee(billEntity.getBorrowCapital().subtract(billEntity.getReceivedCapital()).toString())
                    .setPayOffDate(billEntity.getPayOffDate())
                    .setDiscountCapital(billEntity.getDiscountCapital().toString())

                    .setRepaymentCapital(billEntity.getRepaymentCapital().toString())
                    .setBorrowRatio(productInfoByCode.getBorrowRatio().toString())
                    .setProductCode(billEntity.getProductCode())
                    .setReceivedDate(billEntity.getGmtCreate())

                    .setInterest(billEntity.getRepaymentCapital().subtract(billEntity.getBorrowCapital()).toString())
                    .setOverdueDays(CalculatorUtils.overDueDays(billEntity.getRepaymentDate(), billEntity.getPayOffDate()))
                    .setExtensionCount(billEntity.getExtensionCount());
            billVOList.add(billVO);
        }

        return response.ok().putData(billVOList);
    }

    @Override
    @TimerRecord
    public Response<List<BillVO>> queryByUserCodes(List<String> userCodes) {
        Response<List<BillVO>> response = new Response<>();
        List<TTradeEntity> tradeEntityList = tradeDao.selectListByUserCodes(userCodes);
        if (CollectionUtils.isEmpty(tradeEntityList)) {
            return Response.ok().putData(null);
        }
        List<String> tradeNos = tradeEntityList.parallelStream().map(TTradeEntity::getTradeNo).collect(Collectors.toList());
        List<BillVO> billVOList = new ArrayList<>();
        List<TBillEntity> billEntityList = billDao.selectListByTradeNos(tradeNos);

        for (TBillEntity billEntity : billEntityList) {
            BillVO billVO = new BillVO()
                    .setBillNo(billEntity.getBillNo())
                    .setTradeNo(billEntity.getTradeNo())
                    .setBorrowCapital(billEntity.getBorrowCapital().toString())
                    .setReceivedCapital(billEntity.getReceivedCapital().toString())
                    .setProductCategory(billEntity.getProductCategory())

                    .setCurrentPeriod(billEntity.getCurrentPeriod())
                    .setPaidCapital(billEntity.getPaidCapital().toString())
                    .setPaidStatus(BillPaidStatusEnum.concertByStatus(billEntity.getPaidStatus()))
                    .setRepaymentDate(TimeUtils.getDate("yyyy-MM-dd", billEntity.getRepaymentDate()))

                    .setServiceFee(billEntity.getBorrowCapital().subtract(billEntity.getReceivedCapital()).toString())
                    .setPayOffDate(billEntity.getPayOffDate())
                    .setDiscountCapital(billEntity.getDiscountCapital().toString())

                    .setRepaymentCapital(billEntity.getRepaymentCapital().toString())
                    .setProductCode(billEntity.getProductCode())
                    .setReceivedDate(billEntity.getGmtCreate())

                    .setInterest(billEntity.getRepaymentCapital().subtract(billEntity.getBorrowCapital()).toString())
                    .setOverdueDays(CalculatorUtils.overDueDays(billEntity.getRepaymentDate(), billEntity.getPayOffDate()))
                    .setExtensionCount(billEntity.getExtensionCount());
            billVOList.add(billVO);
        }

        return response.ok().putData(billVOList);
    }

    @Override
    @TimerRecord
    public Response<List<BillRepaymentDetailVO>> queryBillRepaymentFlowListByTradeNos(List<String> tradeNos) {
        if (CollectionUtils.isEmpty(tradeNos)) {
            return Response.ok().putData(null);
        }

        List<TBillRepaymentDetailEntity> billRepaymentDetailEntityList = repaymentDetailDao.selectByTradeNos(tradeNos);
        if (CollectionUtils.isEmpty(billRepaymentDetailEntityList)) {
            return Response.ok().putData(null);
        }

        List<BillRepaymentDetailVO> billRepaymentDetailVOs = new ArrayList<>();
        for (TBillRepaymentDetailEntity billRepaymentDetailEntity : billRepaymentDetailEntityList) {
            BillRepaymentDetailVO billRepaymentDetailVO = new BillRepaymentDetailVO();
            BeanUtils.copyProperties(billRepaymentDetailEntity, billRepaymentDetailVO);
            billRepaymentDetailVOs.add(billRepaymentDetailVO);
        }

        return Response.ok().putData(billRepaymentDetailVOs);
    }

    private BillVO billBase2BillVO(TradeBase tradeBase, BillBase billBase) {
        BigDecimal totalReceivedCapital = tradeBase.getReceivedTotalCapital();
        BigDecimal totalServiceFee = tradeBase.getTotalServiceFee();

        int totalPeriods = tradeBase.getTotalPeriod();
        BigDecimal receivedCapital = CalculatorUtils.calculateReceivedCapital(totalReceivedCapital, totalPeriods);
        BigDecimal serviceFee = CalculatorUtils.calculateServiceFee(totalServiceFee, totalPeriods);

        BillVO billVO = new BillVO()
                .setBillNo(billBase.getBillNo())
                .setTradeNo(billBase.getTradeNo())
                .setBorrowCapital(billBase.getBorrowCapital().toString())
                .setReceivedCapital(billBase.getReceivedCapital().toString())

                .setTotalPeriod(tradeBase.getTotalPeriod())
                .setCurrentPeriod(billBase.getCurrentPeriod())
                .setPaidCapital(billBase.getPaidCapital().toString())
                .setPaidStatus(billBase.getPaidStatus())
                .setRepaymentDate(TimeUtils.getDate("yyyy-MM-dd", billBase.getRepaymentDate()))

                .setServiceFee(serviceFee.toString())
                .setPayOffDate(billBase.getPayOffDate())
                .setDiscountCapital(billBase.getDiscountCapital().toString())

                .setRepaymentCapital(billBase.getRepaymentCapital().toString())
                .setBorrowRatio(tradeBase.getBorrowRatio().toString())
                .setProductCode(billBase.getProductCode())
                .setReceivedDate(tradeBase.getReceivedDate())

                .setReceivedCapital(receivedCapital.toString())
                .setInterest(billBase.getInterestFee().toString())
                .setPeriodLength(tradeBase.getPeriodLength())
                .setBorrowDurationEnum(TradeBorrowDurationEnum.convertByType(tradeBase.getBorrowDuration()))
                .setExtensionCount(billBase.getExtensionCount())
                .setProductCategory(billBase.getProductCategory());

        BigDecimal overdueFee = BigDecimal.ZERO;
        BigDecimal overdueServiceFee = BigDecimal.ZERO;
        boolean isOverdue = CalculatorUtils.isOverdue(billBase.getRepaymentDate(), billBase.getPayOffDate());
        if (isOverdue) {
            int overdueDays = CalculatorUtils.overDueDays(billBase.getRepaymentDate(), billBase.getPayOffDate());
            billVO.setOverdueDays(overdueDays);
            if (billBase.getPaidStatus().equals(BillPaidStatusEnum.CLEAR_REPAYMENT)) {
                overdueFee = billBase.getOverdueFee();
                overdueServiceFee = billBase.getOverdueServiceFee();
            } else {
                if(tradeBase.getChannelCode().contains("open_api_fx")){
                    overdueFee = CalculatorUtils.calculateOverdueFeeTwoPlace(billBase.getBorrowCapital(), tradeBase.getOverdueRatio(), overdueDays);
                }else{
                    overdueFee = CalculatorUtils.calculateOverdueFee(billBase.getBorrowCapital(), tradeBase.getOverdueRatio(), overdueDays);
                }
                overdueServiceFee = tradeBase.getOverdueServiceFee();
            }
        }
        billVO.setOverdueFee(overdueFee.toString());
        billVO.setOverdueServiceFee(overdueServiceFee.toString());

        //累计应还金额
        BigDecimal repaymentTotalCapital = billBase.getRepaymentCapital().add(overdueFee).add(overdueServiceFee);
        //剩余应还金额
        BigDecimal remainRepaymentCapital = billBase.getPaidStatus().equals(BillPaidStatusEnum.CLEAR_REPAYMENT) ?
                BigDecimal.ZERO : repaymentTotalCapital.subtract(billBase.getPaidCapital());

        billVO.setRepaymentTotalCapital(repaymentTotalCapital.toString());
        billVO.setRemainRepaymentCapital(remainRepaymentCapital.toString());

        List<String> billNos = Lists.newArrayList();
        billNos.add(billVO.getBillNo());
        List<TBillRepaymentDetailEntity> tBillRepaymentDetailEntities = tBillRepaymentDetailDao.selectByBillNos(billNos);
        if (CollectionUtils.isNotEmpty(tBillRepaymentDetailEntities)) {
            billVO.setPaidChannel(tBillRepaymentDetailEntities.get(0).getPaidChannel());
        }
        return billVO;
    }


    @Override
    @TimerRecord
    public POrderPrePaymentResponse getPrePaymentOrder(POrderPrePaymentVO prePaymentVO, Page page) {
        POrderPrePaymentEntity pOrderPrePaymentEntity = new POrderPrePaymentEntity();
        BeanUtils.copyProperties(prePaymentVO, pOrderPrePaymentEntity);
        List<POrderPrePaymentEntity> pOrderPrePaymentEntities = pOrderPrePaymentDao.selectPrePaymentOrder(pOrderPrePaymentEntity, page);
        if (CollectionUtils.isEmpty(pOrderPrePaymentEntities)) {
            return null;
        }
        List<POrderPrePaymentVO> pOrderPrePaymentVOS = pOrderPrePaymentEntities.stream().map(pOrderPrePaymentEntity1 -> {
            POrderPrePaymentVO tmp = new POrderPrePaymentVO();
            BeanUtils.copyProperties(pOrderPrePaymentEntity1, tmp);
            return tmp;
        }).collect(Collectors.toList());

        POrderPrePaymentResponse rsp = new POrderPrePaymentResponse();
        rsp.setPage(page);
        rsp.setpOrderPrePaymentVOS(pOrderPrePaymentVOS);
        return rsp;
    }

    /**
     * 待还款信息 简单查询
     *
     * @param request
     * @return
     */
    @Override
    @TimerRecord
    public Response<BillRepayment2VO> getRepaymentDetail(RepaymentQueryRequest request) {
        if (StringUtils.isEmpty(request.getTradeNo()) && StringUtils.isEmpty(request.getBillNo())) {
            return Response.ok();
        }
        TBillEntity tBillEntity = null;
        if (StringUtils.isEmpty(request.getBillNo())) {
            List<TBillEntity> tBillEntityList = billDao.selectListByTradeNo(request.getTradeNo());
            if (CollectionUtils.isEmpty(tBillEntityList)) {
                return Response.ok();
            }
            tBillEntity = tBillEntityList.get(0);
        } else {
            tBillEntity = billDao.selectOneByBillNo(request.getBillNo());
        }
        TTradeEntity tTradeEntity = tradeDao.selectOneByTradeNo(tBillEntity.getTradeNo());

        Date payOffDate = Objects.equals(tBillEntity.getPaidStatus(), BillPaidStatusEnum.CLEAR_REPAYMENT.getStatus()) ? tBillEntity.getPayOffDate() : new Date();

        boolean isOverdue = CalculatorUtils.isOverdue(tBillEntity.getRepaymentDate(), payOffDate);
        BigDecimal overdueServiceFee = BigDecimal.ZERO;
        BigDecimal overdueFee = BigDecimal.ZERO;
        if (isOverdue) {
            int overdueDays = CalculatorUtils.overDueDays(tBillEntity.getRepaymentDate(), payOffDate);
            overdueServiceFee = tTradeEntity.getOverdueServiceFee();
            overdueFee = CalculatorUtils.calculateOverdueFee(tBillEntity.getBorrowCapital(), tTradeEntity.getOverdueRatio(), overdueDays);
        }

        BigDecimal repaymentTotalCapital = tBillEntity.getRepaymentCapital().add(overdueFee).add(overdueServiceFee);
        BigDecimal remainRepaymentCapital = repaymentTotalCapital.subtract(tBillEntity.getPaidCapital());

        BillRepayment2VO billRepayment2VO = new BillRepayment2VO();
        billRepayment2VO.setUserCode(tTradeEntity.getUserCode());
        billRepayment2VO.setTradeNo(tBillEntity.getTradeNo());
        billRepayment2VO.setBillNo(tBillEntity.getBillNo());
        billRepayment2VO.setProductCategory(tBillEntity.getProductCategory());
        billRepayment2VO.setRepaymentTotalCapital(repaymentTotalCapital);
        billRepayment2VO.setBorrowCapital(tBillEntity.getBorrowCapital());
        billRepayment2VO.setInterestFee(tBillEntity.getInterestFee());
        billRepayment2VO.setOverdueServiceFee(overdueServiceFee);
        billRepayment2VO.setOverdueFee(overdueFee);
        billRepayment2VO.setPaidCapital(tBillEntity.getPaidCapital());
        billRepayment2VO.setDiscountCapital(tBillEntity.getDiscountCapital());
        billRepayment2VO.setRemainRepaymentCapital(remainRepaymentCapital);

        return Response.ok().putData(billRepayment2VO);
    }

    /**
     * 待还款信息 试算
     *
     * @param request
     * @return
     */
    @Override
    @TimerRecord
    public Response<BillRepayment2VO> getRepaymentDetail(RepaymentTrialRequest request) {
        if (StringUtils.isEmpty(request.getTradeNo()) && StringUtils.isEmpty(request.getBillNo())) {
            return Response.ok();
        }
        TBillEntity tBillEntity = null;
        if (StringUtils.isEmpty(request.getBillNo())) {
            List<TBillEntity> tBillEntityList = billDao.selectListByTradeNo(request.getTradeNo());
            if (CollectionUtils.isEmpty(tBillEntityList)) {
                return Response.ok();
            }
            tBillEntity = tBillEntityList.get(0);
        } else {
            tBillEntity = billDao.selectOneByBillNo(request.getBillNo());
        }
        TTradeEntity tTradeEntity = tradeDao.selectOneByTradeNo(tBillEntity.getTradeNo());

        Date payOffDate = null;
        if (Objects.equals(tBillEntity.getPaidStatus(), BillPaidStatusEnum.CLEAR_REPAYMENT.getStatus())) {
            payOffDate = tBillEntity.getPayOffDate();
        } else if (request.getPlannedRepaymentDate() != null) {
            payOffDate = request.getPlannedRepaymentDate();
        } else {
            payOffDate = new Date();
        }

        boolean isOverdue = CalculatorUtils.isOverdue(tBillEntity.getRepaymentDate(), payOffDate);
        BigDecimal overdueServiceFee = BigDecimal.ZERO;
        BigDecimal overdueFee = BigDecimal.ZERO;
        if (isOverdue) {
            int overdueDays = CalculatorUtils.overDueDays(tBillEntity.getRepaymentDate(), payOffDate);
            overdueServiceFee = tTradeEntity.getOverdueServiceFee();
            overdueFee = CalculatorUtils.calculateOverdueFee(tBillEntity.getBorrowCapital(), tTradeEntity.getOverdueRatio(), overdueDays);
        }

        //累计应还金额
        BigDecimal repaymentTotalCapital = tBillEntity.getRepaymentCapital().add(overdueFee).add(overdueServiceFee);
        //剩余应还金额
        BigDecimal remainRepaymentCapital = repaymentTotalCapital.subtract(tBillEntity.getPaidCapital());
        if (request.getCapital() != null) {
            remainRepaymentCapital = remainRepaymentCapital.subtract(request.getCapital());
        }
        if (request.getDiscountCapital() != null) {
            remainRepaymentCapital = remainRepaymentCapital.subtract(request.getDiscountCapital());
        }

        BillRepayment2VO billRepayment2VO = new BillRepayment2VO();
        billRepayment2VO.setUserCode(tTradeEntity.getUserCode());
        billRepayment2VO.setTradeNo(tBillEntity.getTradeNo());
        billRepayment2VO.setBillNo(tBillEntity.getBillNo());
        billRepayment2VO.setProductCategory(tBillEntity.getProductCategory());
        billRepayment2VO.setRepaymentTotalCapital(repaymentTotalCapital);
        billRepayment2VO.setBorrowCapital(tBillEntity.getBorrowCapital());
        billRepayment2VO.setInterestFee(tBillEntity.getInterestFee());
        billRepayment2VO.setOverdueServiceFee(overdueServiceFee);
        billRepayment2VO.setOverdueFee(overdueFee);
        billRepayment2VO.setPaidCapital(tBillEntity.getPaidCapital());
        billRepayment2VO.setDiscountCapital(tBillEntity.getDiscountCapital());
        billRepayment2VO.setRemainRepaymentCapital(remainRepaymentCapital);

        return Response.ok().putData(billRepayment2VO);
    }


    @Override
    @TimerRecord
    public Response<List<BillVO>> queryBillByTradeNo(String tradeNo) {
        Response<List<BillVO>> response = new Response<>();
        List<TBillEntity> tBillEntities = billDao.selectListByTradeNo(tradeNo);
        if (CollectionUtils.isEmpty(tBillEntities)) {
            LOGGER.error("账单不存在,tradeNo:{}", tradeNo);
            return response.ok().putData(null);
        }
        List<BillVO> billVOList = new ArrayList<>();
        for (TBillEntity tBillEntity : tBillEntities) {
            BillVO billVO = billEntity2BillVO(tBillEntity);
            billVOList.add(billVO);
        }
        return Response.ok().putData(billVOList);
    }


    private BillVO billEntity2BillVO(TBillEntity tBillEntity){

        BillVO billVO = null;
        if(tBillEntity != null){
            ProductDto productDto = productIntegrationService.getProductInfoByCode(tBillEntity.getProductCode());

            billVO = new BillVO();
            BigDecimal totalReceivedCapital = tBillEntity.getReceivedCapital();
            BigDecimal totalServiceFee = tBillEntity.getBorrowServiceFee();

            int totalPeriods = tBillEntity.getCurrentPeriod();
            BigDecimal receivedCapital = CalculatorUtils.calculateReceivedCapital(totalReceivedCapital, totalPeriods);
            BigDecimal serviceFee = CalculatorUtils.calculateServiceFee(totalServiceFee, totalPeriods);

            billVO = new BillVO()
                    .setBillNo(tBillEntity.getBillNo())
                    .setTradeNo(tBillEntity.getTradeNo())
                    .setBorrowCapital(tBillEntity.getBorrowCapital().toString())
                    .setReceivedCapital(tBillEntity.getReceivedCapital().toString())

                    .setTotalPeriod(tBillEntity.getCurrentPeriod())
                    .setCurrentPeriod(tBillEntity.getCurrentPeriod())
                    .setPaidCapital(tBillEntity.getPaidCapital().toString())
                    .setPaidStatus(BillPaidStatusEnum.concertByStatus(tBillEntity.getPaidStatus()))
                    .setRepaymentDate(TimeUtils.getDate("yyyy-MM-dd", tBillEntity.getRepaymentDate()))

                    .setServiceFee(serviceFee.toString())
                    .setPayOffDate(tBillEntity.getPayOffDate())
                    .setDiscountCapital(tBillEntity.getDiscountCapital().toString())

                    .setRepaymentCapital(tBillEntity.getRepaymentCapital().toString())
                    .setBorrowRatio(productDto.getBorrowRatio().toString())
                    .setProductCode(tBillEntity.getProductCode())
                    .setReceivedDate(tBillEntity.getGmtCreate())

                    .setReceivedCapital(receivedCapital.toString())
                    .setInterest(tBillEntity.getInterestFee().toString())
                    .setPeriodLength(7)
                    .setBorrowDurationEnum(TradeBorrowDurationEnum.DAY)
                    .setExtensionCount(tBillEntity.getExtensionCount())
                    .setProductCategory(tBillEntity.getProductCategory());

            BigDecimal overdueFee = BigDecimal.ZERO;
            BigDecimal overdueServiceFee = BigDecimal.ZERO;
            boolean isOverdue = CalculatorUtils.isOverdue(tBillEntity.getRepaymentDate(), tBillEntity.getPayOffDate());
            if (isOverdue) {
                int overdueDays = CalculatorUtils.overDueDays(tBillEntity.getRepaymentDate(), tBillEntity.getPayOffDate());
                billVO.setOverdueDays(overdueDays);
                if (tBillEntity.getPaidStatus().equals(BillPaidStatusEnum.CLEAR_REPAYMENT)) {
                    overdueFee = tBillEntity.getOverdueFee();
                } else {
                    overdueFee = CalculatorUtils.calculateOverdueFee(tBillEntity.getBorrowCapital(), productDto.getOverdueRatio(), overdueDays);
                }
                overdueServiceFee = tBillEntity.getOverdueServiceFee();
            }
            billVO.setOverdueFee(overdueFee.toString());
            billVO.setOverdueServiceFee(overdueServiceFee.toString());

            //累计应还金额
            BigDecimal repaymentTotalCapital = tBillEntity.getRepaymentCapital().add(overdueFee).add(overdueServiceFee);
            //剩余应还金额
            BigDecimal remainRepaymentCapital = tBillEntity.getPaidStatus().equals(BillPaidStatusEnum.CLEAR_REPAYMENT) ?
                    BigDecimal.ZERO : repaymentTotalCapital.subtract(tBillEntity.getPaidCapital());

            billVO.setRepaymentTotalCapital(repaymentTotalCapital.toString());
            billVO.setRemainRepaymentCapital(remainRepaymentCapital.toString());

            List<String> billNos = Lists.newArrayList();
            billNos.add(billVO.getBillNo());
        }
        return billVO;
    }
}
